package com.juma.cartridge.rlock.fair;

import java.util.ArrayList;
import java.util.List;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.util.Pool;

import com.juma.cartridge.rlock.LockNode;
import com.juma.cartridge.rlock.RedisCaller;
import com.juma.cartridge.rlock.RedisExecutor;

/**
 * 锁队例
 * @ClassName LockQueue
 * @Description
 * @Author zhuangguangyou
 * @Date 2019年8月1日 上午11:41:29
 * @Version 1.0
 *
 */
public class LockQueue {

	private Pool<Jedis> pool;
	
	private String name;
	
	public LockQueue(String name,Pool<Jedis> pool) {
		this.name = name;
		this.pool = pool;
	}
	
	public void appendNode(final LockNode node) {
		redisExecute(new RedisExecutor(){
			@Override
			public void execute(Jedis jedis) {
				jedis.rpush(name, node.toString());
			}
		});
	}
	
	/**
	 * 获取队例头部的锁节点
	 * @return
	 */
	public LockNode getHead() {
		
		String storeValue = redisCall(new RedisCaller<String>(){
			@Override
			public String call(Jedis jedis) {
				return jedis.lindex(name,0);
			}
		});
		return LockNode.parseOf(storeValue);
	}
	
	/**
	 * 获取指定区域的锁节点
	 * @param index
	 * @return
	 */
	public List<LockNode> getNodes(final int start,final int end) {
		List<String> storeValues = redisCall(new RedisCaller<List<String>>(){
			@Override
			public List<String> call(Jedis jedis) {
				return jedis.lrange(name,start,end);
			}
		});
		
		List<LockNode> nodes = new ArrayList<LockNode>(storeValues.size());
		for (String sv:storeValues) {
			nodes.add(LockNode.parseOf(sv));
		}
		return nodes;
	}
	
	/**
	 * 获取指定位置的锁节点
	 * @param index
	 * @return
	 */
	public LockNode getNode(final int index) {
		String storeValue = redisCall(new RedisCaller<String>(){
			@Override
			public String call(Jedis jedis) {
				return jedis.lindex(name,index);
			}
		});
		return LockNode.parseOf(storeValue);
	}
	
	/**
	 * 更新指定位置的节点信息
	 * @param index 
	 * @param node
	 */
	public void setNode(final int index,final LockNode node) {
		redisExecute(new RedisExecutor(){
			@Override
			public void execute(Jedis jedis) {
				jedis.lset(name, index, node.toString());
			}
		});
	}
	
	/**
	 * 删除指定锁节点
	 * @param node
	 */
	public void removeNode(final LockNode node) {
		redisExecute(new RedisExecutor(){

			@Override
			public void execute(Jedis jedis) {
				jedis.lrem(name, 1, node.toString());
			}
		});
	}
	
	/**
	 * 移动头部元素,用第二个元素替代
	 * @param head
	 * @param second
	 */
	public void moveHead(final LockNode head,final LockNode next) {
		if(head==null) {
			return;
		}
		redisExecute(new RedisExecutor(){

			@Override
			public void execute(Jedis jedis) {
				Transaction trans = jedis.multi();
				if(next!=null) {
					trans.lset(name, 1, next.toString());	
				}
				trans.lrem(name, 1, head.toString());
				trans.exec();
			}
		});
	}
	
	/**
	 * 获取当前锁队列中的节排队节点数
	 * @return
	 */
	public long nodeCount() {
		Long len = redisCall(new RedisCaller<Long>(){
			@Override
			public Long call(Jedis jedis) {
				return jedis.llen(name);
			}
		});
		return len;
	}
	
	
	private <T> T redisCall(RedisCaller<T> caller) {
		if (caller==null) {
			return null;
		}
		Jedis jedis = null; 
		try {
			jedis = pool.getResource();
			return caller.call(jedis);
		}finally {
			if(jedis!=null) {
				jedis.close();
			}
		}
	}
	
	
	private void redisExecute(RedisExecutor executor) {
		if (executor==null) {
			return;
		}
		Jedis jedis = null;
		try {
			jedis = pool.getResource();
			executor.execute(jedis);
		}finally {
			if(jedis!=null) {
				jedis.close();
			}
		}
	}
}
